<?php

namespace app\common\service;

use app\admin\model\InventoryChangeRecord;
use app\admin\model\ProductDiscount;
use app\admin\model\ProductPrice;
use app\api\logic\CacheLogic;
use think\facade\Db;
use think\facade\Log;

class Inventory
{
    /**
     *  锁定库存
     */
    public function lockInventory($order, $is_sale = 1)
    {
        Log::info(' [lockInventory] 锁定库存 订单信息：' . json_encode($order));
        $insert_param = [
            'inventory_id' => 0,
            'business_tabel_name' => 'order',
            'business_table_id' => $order['id'] ?? 0,
            'business' => '库存锁定',
            'remark' => '库存锁定',
            'number' => 0,
            'operator_id' => $order['operator_id'] ?? null,
        ];
        Db::startTrans();
        try {
            // 1. 获取订单中的所有商品信息
            $product_list = Db::name('order_item')
                ->where([
                    'order_id' => $order['id'],
                    'is_del' => 0
                ])
                ->where('pending_quantity', '>', 0)
                ->field('id,order_id,product_id, warehouse_id, quantity, pending_quantity,arrival_date, is_futures')
                ->select()
                ->toArray();
            // 2. 遍历订单中的每个商品
            foreach ($product_list as $product) {
                Log::info(' [lockInventory] 锁定库存 订单行信息：' . json_encode($product));
                // 3. 查询符合条件的库存记录
                $inventoryList = Db::name('inventory')
                    ->field('id,productid,wid,arrival_date,is_futures,available_qty,lock_qty,allow_zero_stock_sale')
                    ->whereFindInSet('wid', $product['warehouse_id'])
                    ->where([
                        'is_del' => 0,
                        'productid' => $product['product_id'],
                        'arrival_date' => $product['arrival_date'],
                        'is_futures' => $product['is_futures'],
                    ])
                    ->where(function ($query) use ($is_sale) {
                        if ($is_sale == 1) {
                            $query->where('is_sale', 1);
                        }
                    })
                    ->whereRaw('(available_qty - lock_qty) > 0 or allow_zero_stock_sale = 1')
                    ->lock(true)
                    ->select()
                    ->toArray();
                // 4. 如果找到可用库存
                if ($inventoryList) {
                    // 5. 需要锁定的总数量
                    $wait_lock_qty = $product['pending_quantity'];
                    Log::info(' [lockInventory] 锁定库存 订单行待锁定数：' . $wait_lock_qty);
                    // 6. 遍历可用库存记录，逐个锁定
                    foreach ($inventoryList as $inventory) {
                        Log::info(' [lockInventory] 锁定库存 订单行匹配的库存信息：' . json_encode($inventory));
                        // 如果已经锁定完所需数量，退出循环
                        if ($wait_lock_qty <= 0) {
                            break;
                        }

                        if ($inventory['allow_zero_stock_sale'] == 1) {
                            Db::name('inventory')
                                ->where('id', $inventory['id'])
                                ->inc('lock_qty', $wait_lock_qty)
                                ->update();
                            $insert_param['inventory_id'] = $inventory['id'];
                            $insert_param['number'] = $wait_lock_qty;
                            $this->insertInventoryChanggeData($insert_param);
                            Log::info(' [lockInventory] order_id: ' . $product['order_id'] . ' order_iterm_id :' . $product['id'] . '  inventory id: ' . $inventory['id'] . ' 锁定数量： ' . $wait_lock_qty . ' 原存库锁定数： ' . $inventory['lock_qty']);
                            Log::info(' [shopify] Lock inventory  id: ' . $inventory['id'] . ' 锁定数量： ' . $wait_lock_qty);
                            $wait_lock_qty = 0;
                            continue;
                        }
                        // 计算当前库存记录的实际可用数量
                        $available = $inventory['available_qty'] - $inventory['lock_qty'];

                        // 如果当前库存足够锁定剩余所需数量
                        if ($wait_lock_qty <= $available) {
                            // 更新锁定数量
                            Db::name('inventory')
                                ->where('id', $inventory['id'])
                                ->inc('lock_qty', $wait_lock_qty)
                                ->update();
                            $insert_param['inventory_id'] = $inventory['id'];
                            $insert_param['number'] = $wait_lock_qty;
                            $this->insertInventoryChanggeData($insert_param);
                            Log::info(' [lockInventory] order_id: ' . $product['order_id'] . ' order_iterm_id :' . $product['id'] . ' inventory id: ' . $inventory['id'] . ' 锁定数量： ' . $wait_lock_qty . ' 原存库锁定数： ' . $inventory['lock_qty']);
                            Log::info(' [shopify] Lock inventory  id: ' . $inventory['id'] . ' 锁定数量： ' . $wait_lock_qty);
                            $wait_lock_qty = 0;
                        } else {
                            // 如果当前库存不够，锁定全部可用数量
                            Db::name('inventory')
                                ->where('id', $inventory['id'])
                                ->inc('lock_qty', $available)
                                ->update();
                            $insert_param['inventory_id'] = $inventory['id'];
                            $insert_param['number'] = $available;
                            $this->insertInventoryChanggeData($insert_param);
                            Log::info(' [lockInventory] order_id: ' . $product['order_id'] . ' order_iterm_id :' . $product['id'] . ' inventory id: ' . $inventory['id'] . ' 锁定数量： ' . $wait_lock_qty . ' 原存库锁定数： ' . $inventory['lock_qty']);
                            Log::info(' [shopify] Lock inventory  id: ' . $inventory['id'] . ' 锁定数量： ' . $available);
                            $wait_lock_qty -= $available;
                        }
                    }
                    // 7. 检查是否所有数量都已锁定
                    if ($wait_lock_qty > 0) {
                        throw new \Exception('库存不足');
                    }
                } else {
                    // 没有找到可用库存
                    throw new \Exception('无可用库存');
                }
            }
            Db::commit();
            return true;
        } catch (\Exception $e) {
            // 记录错误日志
            Log::info(' [lockInventory] Lock inventory failed: ' . $e->getMessage() . ' order_id: ' . $order['id']);
            Log::error(' [shopify] Lock inventory failed: ' . $e->getMessage() . ' order_id: ' . $order['id']);
            Db::rollback();
            return false;
        }
    }


    /**
     * @describe 锁定库存(按库存四要素锁定)
     * @author: Bobo
     * @date: 2025-08-22 11:12:46 
     * @param [type] @required
     * @return Renderable
     */
    public function lockInventoryByItem(array $product_list)
    {
        $insert_param = [
            'inventory_id' => 0,
            'business_tabel_name' => 'order',
            'business_table_id' => 0,
            'business' => '库存锁定',
            'remark' => '库存锁定',
            'number' => 0,
        ];
        Db::startTrans();
        try {
            foreach ($product_list as $product) {
                if ($product['quantity'] == 0) {
                    continue;
                }
                $insert_param['business_table_id'] = $product['order_id'] ?? 0;
                $insert_param['operator_id'] = $product['operator_id'] ?? null;
                Log::info(' [lockInventoryByItem] 锁定库存 商品信息：' . json_encode($product));
                $inventoryList = Db::name('inventory')
                    ->field('id,productid,wid,arrival_date,is_futures,available_qty,lock_qty,allow_zero_stock_sale')
                    ->whereFindInSet('wid', $product['warehouse_id'])
                    ->where([
                        'is_del' => 0,
                        'productid' => $product['product_id'],
                        'arrival_date' => $product['arrival_date'],
                        'is_futures' => $product['is_futures']
                    ])
                    ->whereRaw('(available_qty - lock_qty) > 0 or allow_zero_stock_sale = 1')
                    ->order('is_sale desc,lock_qty asc')
                    ->lock(true)
                    ->select()
                    ->toArray();

                if ($inventoryList) { // 有库存
                    $wait_lock_qty = $product['quantity'];
                    Log::info(' [lockInventoryByItem] 锁定库存 商品行待锁定数：' . $wait_lock_qty);
                    foreach ($inventoryList as $inventory) {
                        if ($wait_lock_qty <= 0) {
                            break;
                        }
                        Log::info(' [lockInventoryByItem] 锁定库存 商品行匹配的库存信息：' . json_encode($inventory));
                        if ($inventory['allow_zero_stock_sale'] == 1) {
                            Db::name('inventory')->where('id', $inventory['id'])->inc('lock_qty', $wait_lock_qty)->update();
                            $insert_param['inventory_id'] = $inventory['id'];
                            $insert_param['number'] = $wait_lock_qty;
                            $this->insertInventoryChanggeData($insert_param);
                            $wait_lock_qty = 0;
                            Log::info(' [lockInventoryByItem] 锁定库存ID:' . $inventory['id'] . ' 库存信息：' . json_encode($inventory) . ' 锁定数量：' . $wait_lock_qty . ' 是否锁定零库存：' . $inventory['allow_zero_stock_sale']);
                            continue;
                        }

                        $available = $inventory['available_qty'] - $inventory['lock_qty'];
                        if ($wait_lock_qty <= $available) {
                            Db::name('inventory')->where('id', $inventory['id'])->inc('lock_qty', $wait_lock_qty)->update();
                            $insert_param['inventory_id'] = $inventory['id'];
                            $insert_param['number'] = $wait_lock_qty;
                            $this->insertInventoryChanggeData($insert_param);
                            $wait_lock_qty = 0;
                            Log::info(' [lockInventoryByItem] 锁定库存ID:' . $inventory['id'] . ' 库存信息：' . json_encode($inventory) . ' 锁定数量：' . $wait_lock_qty . ' 是否锁定零库存：' . $inventory['allow_zero_stock_sale']);
                        } else {
                            Db::name('inventory')->where('id', $inventory['id'])->inc('lock_qty', $available)->update();
                            $insert_param['inventory_id'] = $inventory['id'];
                            $insert_param['number'] = $available;
                            $this->insertInventoryChanggeData($insert_param);
                            $wait_lock_qty -= $available;
                            Log::info(' [lockInventoryByItem] 锁定库存ID:' . $inventory['id'] . ' 库存信息：' . json_encode($inventory) . ' 锁定数量：' . $available . ' 是否锁定零库存：' . $inventory['allow_zero_stock_sale']);
                        }
                    }
                    if ($wait_lock_qty > 0) {
                        throw new \Exception('库存不足');
                    }
                } else {
                    throw new \Exception('无可用库存');
                }
            }
            Db::commit();
            return true;
        } catch (\Throwable $th) {
            Db::rollback();
            return false;
        }
    }

    /**
     * @describe 解锁库存
     * @author: Bobo
     * @date: 2025-07-28 14:39:40
     * @param [type]
     * @return Renderable
     */
    public function unlockInventory($conditions)
    {
        try {
            $insert_param = [
                'inventory_id' => 0,
                'business_tabel_name' => 'order',
                'business_table_id' => 0,
                'business' => '解锁库存',
                'remark' => '解锁库存',
                'number' => 0,
            ];
            foreach ($conditions as $condition) {
                $insert_param['business_table_id'] = $condition['order_id'] ?? 0;
                $insert_param['operator_id'] = $condition['operator_id'] ?? null;
                if ($condition['quantity'] <= 0) {
                    throw new \Exception('释放数量小于零');
                }
                # 四要素 查询库存
                $inventory = Db::name('inventory')->where([
                    'arrival_date' => $condition['arrival_date'],
                    'productid' => $condition['product_id'],
                    'is_futures' => $condition['is_futures']

                ])->where('lock_qty', '<>', 0)->whereFindInSet('wid', $condition['wid'])->order('is_sale desc,lock_qty desc')->select();

                if (empty($inventory)) {
                    throw new \Exception('无可用库存');
                }
                $unlock_quantity = $condition['quantity'];
                foreach ($inventory as $item) {
                    #锁定库存足够归还
                    if ($unlock_quantity > 0) {
                        if ($item['lock_qty'] >= $unlock_quantity) {
                            Db::name('inventory')->where('id', $item['id'])->dec('lock_qty', $unlock_quantity)->update();
                            $insert_param['inventory_id'] = $item['id'];
                            $insert_param['number'] = $unlock_quantity;
                            $this->insertInventoryChanggeData($insert_param);
                            Log::info(' [unlockInventory] 释放库存 条件：' . json_encode($condition) . ' 库存 id ：' . $item['id'] . ' 原库存锁定数量：' . $item['lock_qty'] . ' 释放数量 ：' . $unlock_quantity);
                            Log::info(' [shopify] 释放库存 条件：' . json_encode($condition) . ' 库存 id ：' . $item['id'] . ' 原库存锁定数量：' . $item['lock_qty'] . ' 释放数量 ：' . $unlock_quantity);
                            $unlock_quantity = 0;
                        } else {
                            #锁定库存不够，继续更新下一条
                            if ($item['lock_qty'] > 0) {
                                Db::name('inventory')->where('id', $item['id'])->dec('lock_qty', $item['lock_qty'])->update();
                                $insert_param['inventory_id'] = $item['id'];
                                $insert_param['number'] = $item['lock_qty'];
                                $this->insertInventoryChanggeData($insert_param);
                                $unlock_quantity -= $item['lock_qty'];
                                Log::info(' [unlockInventory] 释放库存 条件：' . json_encode($condition) . ' 库存 id ：' . $item['id'] . ' 原库存锁定数量：' . $item['lock_qty'] . ' 释放数量 ：' . $item['lock_qty']);
                                Log::info(' [shopify] 释放库存 条件：' . json_encode($condition) . ' 库存 id ：' . $item['id'] . ' 原库存锁定数量：' . $item['lock_qty'] . ' 释放数量 ：' . $item['lock_qty']);
                            } elseif ($item['lock_qty'] < 0) {
                                Db::name('inventory')->where('id', $item['id'])->dec('lock_qty', $unlock_quantity)->update();
                                $insert_param['inventory_id'] = $item['id'];
                                $insert_param['number'] = $unlock_quantity;
                                $this->insertInventoryChanggeData($insert_param);
                                Log::info(' [unlockInventory] 释放库存 条件：' . json_encode($condition) . ' 库存 id ：' . $item['id'] . ' 原库存锁定数量：' . $item['lock_qty'] . ' 释放数量 ：' . $unlock_quantity);
                                Log::info(' [shopify] 释放库存 条件：' . json_encode($condition) . ' 库存 id ：' . $item['id'] . ' 原库存锁定数量：' . $item['lock_qty'] . ' 释放数量 ：' . $unlock_quantity);
                                $unlock_quantity = 0;
                            }
                        }
                    }
                }
                # 所有库存全部还完 还不足以释放数量
                if ($unlock_quantity > 0) {
                    throw new \Exception('库存不足');
                }
            }
            $cacheLogic = new CacheLogic();
            $cacheLogic->clearCache(6); // 清除C端产品缓存
        } catch (\Exception $e) {
            Log::error(" [unlockInventory]  释放库存失败: {$e->getMessage()}");
            Log::error(" [shopify]  释放库存失败: {$e->getMessage()}");
            return false;
        }
        return true;
    }
    #库存锁定失败 更新订单 和订单行状态
    public function updateOrderAfterLockInventoryFail($id)
    {
        #锁定失败 标记异常
        $orderInfo = \app\api\model\Order::where('id', $id)->where('is_del', 0)->find();
        if ($orderInfo) {
            $orderInfo->review_node = 1;
            $orderInfo->exceptionstatus = 1;
            $orderInfo->save();
            \app\api\model\OrderItem::where('order_id', $id)->update(['exceptionstatus' => 1]);
        }
    }

    public function insertInventoryChanggeData($param)
    {
        $inventory_change_base = [
            'inventory_id' => $param['inventory_id'],
            'business_tabel_name' => $param['business_tabel_name'],
            'business_table_id' => $param['business_table_id'],
            'business' => $param['business'] ?? '',
            'remark' => $param['remark'] ?? '',
            'number' => $param['number'],
            'creator' => $param['operator_id'] ?? null,
            'create_time' => date("Y-m-d H:i:s"),
        ];
        $oInventoryModel = new InventoryChangeRecord();
        return $oInventoryModel->insertGetId($inventory_change_base);
    }
    public function insertInventoryPrice($inventoryInfo, $newId, $wid, $operator_id)
    {
        $partent_wid  = $wid;
        $discount_insert = [];
        // 获取原有价格
        $oProductPriceModel = ProductPrice::with('discount')->where([
            ['inventory_id', '=', $inventoryInfo['id']],
            ['wid', '=', $partent_wid],
            ['is_del', '=', '0']
        ])->select();

        if ($oProductPriceModel) {
            foreach ($oProductPriceModel as $item) {
                $newProductPriceModel = new ProductPrice();
                $newProductPriceModel->inventory_id = $newId;
                $newProductPriceModel->wid = $wid;
                $newProductPriceModel->transaction_currency_id = $item->transaction_currency_id;
                $newProductPriceModel->price = $item->price;
                $newProductPriceModel->first_leg_logistics_fee = $item->first_leg_logistics_fee;
                $newProductPriceModel->is_del = 0;
                $newProductPriceModel->creator = $operator_id;
                $newProductPriceModel->create_time = date('Y-m-d H:i:s');
                if (!$newProductPriceModel->save()) {
                    throw new Exception("库存价格存储失败！");
                }
                if ($item->discount) {
                    foreach ($item->discount as $discount) {
                        $discount_insert[] = [
                            'price_id' => $newProductPriceModel->id,
                            'level' => $discount->level,
                            'num' => $discount->num,
                            'rate' => $discount->rate,
                            'price' => $discount->price,
                            'creator' => $operator_id,
                            'create_time' => date('Y-m-d H:i:s')
                        ];
                    }
                }
            }
        }


        if (count($discount_insert) > 0) {
            $discount_result = ProductDiscount::insertAll($discount_insert);
            if (!$discount_result) {
                throw new Exception("库存折扣存储失败！");
            }
        }
    }
}
